
    use: 'ie.ondevice.objectkit.utility.compiler.ClassPath';
    use: 'ie.ondevice.objectkit.utility.compiler.ClassLoader';
    use: 'ie.ondevice.objectkit.utility.compiler.CompilerListener';
    use: 'ie.ondevice.objectkit.utility.compiler.ClassFile';
    use: 'ie.ondevice.objectkit.utility.compiler.ClassWriter';

    Compiler.implement
    (
        {
          
            /**
             * @public
             * All of the source code loaded and tranformed during compilation
             * @type {String}
             * @see #compile
             */
            compiledCode: null  
        
            /**
             * @private
             * A registry of class files mapped by canonical class names
             * @type {Object}
             */
        ,   classMap: null
        
            /**
             * @private
             * The ordered list of class files resulting from a successful
             * compilation.
             * @type {Array}
             */
        ,   classList: null   
            
            /**
             * @private
             * The class writer responsible for transforming source code
             * @type {ClassWriter}
             */
        ,   classWriter: null   
            
            /**
             * Collate all the source code required to support a particular
             * class.
             * @param {String} entryClass    A canonical class name
             * @return {String} The compiled code
             */
        ,   compile: function (entryClass) 
            {
                try 
                {
                    this.classList= [];
                    this.introduce(entryClass);
                    this.calculateDependencies(entryClass);
                    return this.compiledCode;
                }
                catch (thrown) 
                {
                    console.log(thrown.stack || thrown);
                }
                finally
                {
                    console.log('complete:\n\n\t' + this.classList.join('\n\t'));
                }
            }
            
            /**
             * @private
             * Introduce a class file to the compilers classMap and
             * examine it for dependencies
             * @param {String} canonicalName    A canonical class name
             * @return {void}
             */
        ,   introduce: function (canonicalName) 
            {
                var classFile= this.classLoader.load(canonicalName);
                this.classMap[canonicalName]= classFile;
                this.examine(classFile);
            }
            
            /**
             * @private
             * Inspect a class file for its dependencies. If a class files
             * dependency has not already been recorded in the class map,
             * introduce it.
             * @param {ClassFile} classFile   
             * @return {void}
             */
        ,   examine: function (classFile) 
            {
                var dependencies= classFile.getDependencies()
                ,   canonicalName
                ,   i= 0
                ,   n= dependencies.length

                for (; i < n; i++) 
                {
                    canonicalName= dependencies[i]
                    if (false === canonicalName in this.classMap)
                    {
                        this.introduce(canonicalName);
                    } 
                }
            }
            
            /**
             * Calculate the order in which dependencies must be satisfied in
             * order to support a particular class.
             * 
             * @param {String} entryClass
             * @return {Array.<ClassFile>} A sorted list of class dependencies
             * @throws {Error} 
             */
        ,   calculateDependencies: function (canonicalName) 
            {
                var result= []
                ,   seen= []
                
                // bootstrap the process
                this.resolveDependencies(canonicalName, result, seen);
                this.classList= result;
            }
            
            /**
             * @private
             * 
             * @param {String} canonicalName    The class to resol
             * @param {Object} classMap         A class map with knowl
             * @param {Array} result
             * @param {Array} seen
             * @return {void}
             */
        ,   resolveDependencies: function (canonicalName, result, seen)
            {
                var classFile= this.getClass(canonicalName)
                ,   dependencies
                ,   dependency
                 
                if (seen.contains(canonicalName)) 
                    return;
                    
                seen.push(canonicalName);
                dependencies= classFile.getDependencies();

                for (var i= 0, n= dependencies.length; i < n; i++) 
                {
                    dependency= dependencies[i];
                    this.resolveDependencies(dependency, result, seen);
                }
                
                this.transform(classFile);
                result.push(classFile);
            }
            
            
            /**
             * @protected
             * Transform a class files source code by applying the
             * class writer to it. This behaviour can be enabled and disabled
             * by #enableCodeTransform #disableCodeTransform respectively
             * @param {ClassFile} classFile
             * @return {void}
             * @see #enableCodeTransform
             * @see #disableCodeTransform
             * @see #willTransformCode
             */
        ,   transform: function (classFile) 
            {
                this.classWriter.write(classFile);
                this.compiledCode+= classFile.sourceCode;
            }
            
            /**
             * Retrieve a class that the compiler has knowledge of.
             * @param {String} canonicalName    A canonical class name
             * @return {ClassFile}    The class file representing the class
             * @throws {Error}
             */
        ,   getClass: function (canonicalName) 
            {
                if (canonicalName in this.classMap)
                    return this.classMap[canonicalName];
                    
                throw new Error('Could not retrieve class ' + canonicalName);
            }

            /**
             * Set the classpath to use to resolve classes against.
             * @param {String} value
             * @return {void}
             */
        ,   setClasspath: function (value) 
            {
                this.classLoader.setClasspath(value);
            }
            
            /**
             * Set the compilers code rewriter.
             * @param {ClassWriter} value
             * @return {void}
             * @see #enableCodeTransform
             * @see #disableCodeTransform
             * @see #enableDebugger
             * @see #disableDebugger
             */
        ,   setWriter: function (value) 
            {
                this.classWriter= value;
                this.classWriter.setClassProvider(this);
            }
            
            /**
             * Listen to the compilers output
             * @param {CompilerListener} value
             * @return {void}
             */
        ,   setListener: function (value) 
            {
                this.listener= value;
            }
            
            /**
             * Enable source code transformation. 
             * 
             * @return {void}
             */
        ,   enableCodeTransform: function () 
            {
                this.classWriter.enable();
            }
            
            /**
             * Disable source code transformation.
             * @return {void}
             */
        ,   disableCodeTransform: function () 
            {
                 this.classWriter.disable();
            }
            
            /**
             * Enable debugger statements to be written into transformed
             * code.
             * @return {void}
             */
        ,   enableDebugger: function () 
            {
                this.classWriter.enableDebugger();
            }
            
            /**
             * Disable debugger statements from being written into transformed
             * code.
             * @return {void}
             */
        ,   disableDebugger: function () 
            {
                this.classWriter.disableDebugger();
            }
        }
    );
    
    /**
     * 
     * @constructor
     */
    function Compiler () 
    {
        this.classMap= {};
        this.classList= [];
        this.compiledCode= '';
        this.classLoader= new ClassLoader;
        this.setWriter(new ClassWriter);
        this.enableCodeTransform();
        this.disableDebugger();
    };
